#ifndef __M_LOGGER_H__
#define __M_LOGGER_H__

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

/*
    日志器类的设计
        1.抽象出日志器父类
        2.派生出不同方式的日志器子类（同步 & 异步）
*/

#include "util.hpp"
#include "logLevel.hpp"
#include "logMessage.hpp"
#include "format.hpp"
#include "sink.hpp"
#include "looper.hpp"
#include <mutex>
#include <atomic>
#include <vector>
#include <sstream>
#include <unordered_map>
#include <cstdarg>

namespace Yohifo
{
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;

    public:
        Logger(const std::string &name, const LogLevel::Value &level,
               const Formater::ptr formater, const std::vector<LogSink::ptr> &sinks)
            : _logger_name(name), _limit_level(level), _formater(formater), _sinks(sinks)
        {
        }

        // 获取当前日志器的名称
        const std::string &GetLoggerName()
        {
            return _logger_name;
        }

        void Debug(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1.判断等级是否足够
            if (LogLevel::Value::DEBUG < _limit_level)
                return;

            // 2.通过可变参数提取出格式化字符串信息
            // 从 fmt 中提取信息
            va_list ap;
            va_start(ap, fmt);

            // 解析及落地
            parseAndSink(LogLevel::Value::DEBUG, file, line, fmt, ap);
        }

        void Info(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1.判断等级是否足够
            if (LogLevel::Value::INFO < _limit_level)
                return;

            // 2.通过可变参数提取出格式化字符串信息
            // 从 fmt 中提取信息
            va_list ap;
            va_start(ap, fmt);

            // 解析及落地
            parseAndSink(LogLevel::Value::INFO, file, line, fmt, ap);
        }

        void Warning(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1.判断等级是否足够
            if (LogLevel::Value::WARNING < _limit_level)
                return;

            // 2.通过可变参数提取出格式化字符串信息
            // 从 fmt 中提取信息
            va_list ap;
            va_start(ap, fmt);

            // 解析及落地
            parseAndSink(LogLevel::Value::WARNING, file, line, fmt, ap);
        }

        void Error(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1.判断等级是否足够
            if (LogLevel::Value::ERROR < _limit_level)
                return;

            // 2.通过可变参数提取出格式化字符串信息
            // 从 fmt 中提取信息
            va_list ap;
            va_start(ap, fmt);

            // 解析及落地
            parseAndSink(LogLevel::Value::ERROR, file, line, fmt, ap);
        }

        void Fatal(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1.判断等级是否足够
            if (LogLevel::Value::FATAL < _limit_level)
                return;

            // 2.通过可变参数提取出格式化字符串信息
            // 从 fmt 中提取信息
            va_list ap;
            va_start(ap, fmt);

            // 解析及落地
            parseAndSink(LogLevel::Value::FATAL, file, line, fmt, ap);
        }

    protected:
        void parseAndSink(const LogLevel::Value &level, const std::string &file, size_t line, const std::string &fmt, va_list &ap)
        {
            char *str; // 解析成功后的字符串（需要释放内存）
            int ret = vasprintf(&str, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cerr << "vasprintf fail" << std::endl;
                return;
            }

            va_end(ap);

            // 3.获取日志消息
            LogMessage msg(_logger_name, file, line, level, str);

            // 4.将消息进行格式化
            std::stringstream ss;
            _formater->format(ss, msg);

            // 5.日志落地
            Log(ss.str().c_str(), ss.str().size());

            free(str);
        }

        // 不同的子类实现具体接口内容
        virtual void Log(const char *data, size_t len) = 0;

    protected:
        std::mutex _mtx;
        std::string _logger_name; // 日志器名称
        std::atomic<LogLevel::Value> _limit_level;
        Formater::ptr _formater;
        std::vector<LogSink::ptr> _sinks; // 多种日志落地方案
    };

    // 同步日志器类
    class SyncLogger : public Logger
    {
    public:
        SyncLogger(const std::string &name, const LogLevel::Value &level,
                   const Formater::ptr formater, const std::vector<LogSink::ptr> sinks)
            : Logger(name, level, formater, sinks)
        {
        }

    public:
        void Log(const char *data, size_t len) override
        {
            std::unique_lock<std::mutex> lock(_mtx);

            if (_sinks.empty())
                return;

            // 同步：遍历 sinks 落实所有的日志落地方案
            for (auto sink : _sinks)
                sink->log(data, len);
        }
    };

    // 异步日志器类
    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(const std::string &name, const LogLevel::Value &level, const Formater::ptr formater,
                    const std::vector<LogSink::ptr> sinks, const AsyncType &type)
            : Logger(name, level, formater, sinks), _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::RealLog, this, std::placeholders::_1), type))
        {
        }

    public:
        void Log(const char *data, size_t len) override
        {
            // 使用 _looper 中的 push（内部已经实现为线程安全）
            _looper->Push(data, len);
        }

        // 被回调的函数
        void RealLog(Buffer &buffer)
        {
            // 无需加锁，因为此时只有一个异步工作线程

            if (_sinks.empty())
                return;

            // 同步：遍历 sinks 落实所有的日志落地方案
            for (auto sink : _sinks)
                sink->log(buffer.Begin(), buffer.ReadbleSize());
        }

    private:
        AsyncLooper::ptr _looper;
    };

    /*
        扩展：建造者模式（无需指挥者类）
            1.抽象一个日志器建造者类
                - 设置日志类型（同步 / 异步）
                - 将不同类型日志器的创建放到同一个日志器建造者类中完成
            2.派生出具体的建造者类（全局 / 局部）
    */
    enum class LoggerType
    {
        LOGGER_SYNC, // 同步
        LOGGER_ASYNC // 异步
    };

    class LoggerBuilder
    {
    public:
        // 默认为 同步日志器，限制等级为 DEBUG
        LoggerBuilder()
            : _type(LoggerType::LOGGER_SYNC), _limit(LogLevel::Value::DEBUG), _async_type(AsyncType::ASYNC_SAFE)
        {
        }

        void BuildLoggerType(const LoggerType &type)
        {
            _type = type;
        }

        void BuildAsyncType(const AsyncType &type)
        {
            _async_type = type;
        }

        void BuildLoggerName(const std::string &name)
        {
            _name = name;
        }

        void BuildLoggerLimit(const LogLevel::Value &limit)
        {
            _limit = limit;
        }

        void BuildFormat(const std::string &patten)
        {
            // 根据 patten 格式化规则，创建 formater 对象
            _formater = std::make_shared<Formater>(patten);
        }

        // 添加具体的落地方案
        template <class SinkType, class... Args>
        void BulidSink(Args &&...args)
        {
            // 创建一个 sink 对象，然后尾插
            LogSink::ptr psink = SinkFactory::Create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }

        // 建造日志器对象
        virtual Logger::ptr Build() = 0;

    protected:
        LoggerType _type;
        AsyncType _async_type; // 异步日志器的工作模型
        std::string _name;
        LogLevel::Value _limit;
        Formater::ptr _formater;
        std::vector<LogSink::ptr> _sinks;
    };

    // 派生出局部的日志器建造者类
    class LocalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr Build() override
        {
            // 断言，必须要有 日志器名称
            assert(!_name.empty());

            // 特殊情况：_formater 为空
            if (_formater.get() == nullptr)
            {
                // 按照默认格式进行创建
                _formater = std::make_shared<Formater>();
            }

            // 特殊情况：_sinks 为空
            if (_sinks.empty())
            {
                // 默认落地至标准输出
                BulidSink<StdoutSink>();
            }

            // 根据类型创建日志器建造对象
            if (_type == LoggerType::LOGGER_SYNC)
                return std::make_shared<SyncLogger>(_name, _limit, _formater, _sinks);
            else if (_type == LoggerType::LOGGER_ASYNC)
                return std::make_shared<AsyncLogger>(_name, _limit, _formater, _sinks, _async_type);
        }
    };

    /*
        单例日志器管理类（懒汉）
            1.添加日志器
            2.判断日志器是否被管理
            3.获取指定日志器
            4.获取默认日志器
    */

    class LoggerManage
    {
    public:
        static LoggerManage &GetInstance()
        {
            // C++11 之后能保证线程安全
            static LoggerManage eton;
            return eton;
        }

        void Add(Logger::ptr &logger)
        {
            // 不需要判断 logger 是否存在，因为 unordered_map 自带去重
            // 加锁保证线程安全
            std::unique_lock<std::mutex> lock(_mtx);
            _loggers.insert(std::make_pair(logger->GetLoggerName(), logger));
        }

        bool Find(const std::string &name)
        {
            // 加锁保护
            std::unique_lock<std::mutex> lock(_mtx);

            return _loggers.find(name) != _loggers.end();
        }

        Logger::ptr GetLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mtx);

            // 如果不存在，就返回默认的日志器
            return _loggers.find(name) == _loggers.end() ? _root_logger : _loggers[name];
        }

        Logger::ptr Root()
        {
            return _root_logger;
        }

    private:
        // 构造函数私有化
        LoggerManage()
        {
            // 指定日志器名称为 root 其他属性为 [默认]
            std::shared_ptr<Yohifo::LocalLoggerBuilder> builder(new Yohifo::LocalLoggerBuilder);
            builder->BuildLoggerName("root"); // 日志器名称
            _root_logger = builder->Build();

            // 插入 _loggers
            _loggers.insert(std::make_pair(_root_logger->GetLoggerName(), _root_logger));
        }

    private:
        Logger::ptr _root_logger;
        std::unordered_map<std::string, Logger::ptr> _loggers;
        std::mutex _mtx; // 互斥锁
    };

    // 派生出全局的日志器建造者类
    class GlobalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr Build() override
        {
            // 断言，必须要有 日志器名称
            assert(!_name.empty());

            // 特殊情况：_formater 为空
            if (_formater.get() == nullptr)
            {
                // 按照默认格式进行创建
                _formater = std::make_shared<Formater>();
            }

            // 特殊情况：_sinks 为空
            if (_sinks.empty())
            {
                // 默认落地至标准输出
                BulidSink<StdoutSink>();
            }

            // 根据类型创建日志器建造对象
            Logger::ptr logger;
            if (_type == LoggerType::LOGGER_SYNC)
                logger = std::make_shared<SyncLogger>(_name, _limit, _formater, _sinks);
            else if (_type == LoggerType::LOGGER_ASYNC)
                logger = std::make_shared<AsyncLogger>(_name, _limit, _formater, _sinks, _async_type);

            // 添加到单例对象
            LoggerManage::GetInstance().Add(logger);

            return logger;
        }
    };
}

#endif
